/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com */

/*
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "scene.h"
#include "entity.h"

#include <stdio.h>
#include <iostream>
#include <map>

namespace tri {


/**
 * Scene implementation
 */

TScene::TScene():TAbstractEntityParent() , TAbstractEventComponent(), m_Parent(NULL) {}
TScene::~TScene(){
	if (m_Parent != NULL){
		m_Parent->removeScene(getName());
	}
}

void TScene::setName(std::string name){
	m_Name = name;
}

void TScene::show(){
}

void TScene::hide(){
}

std::string TScene::getName() const{
	return m_Name;
}

void TScene::update(){
	emit(tri::UPDATED);
	ConstIterator it = m_EntitySet.begin();
	ConstIterator itEnd = m_EntitySet.end();

	while (it != itEnd) {
		(*it)->update();
		++it;
	}
}

void TScene::render(){
	ConstIterator it = m_EntitySet.begin();
	ConstIterator itEnd = m_EntitySet.end();

	while (it != itEnd) {
		(*it)->render();
		++it;
	}
}

void TScene::onResize(int w, int h){
	
}

TCamera* TScene::getCamera(){
	return &m_Camera;
}

void TScene::removeEntity(TEntity* child){
	if( child != NULL ){
		m_EntitySet.erase(child);
		child->m_Parent = NULL;
	}
}

void TScene::addEntity(TEntity* child){
	if ( child == NULL ){
		return;
	}
	
	if( !hasEntity(child) ){
		if (child->m_Parent != NULL){
			child->m_Parent->removeEntity(child);
		}
		
		m_EntitySet.insert(child);
		child->m_Parent = this;
	}
}

void TScene::removeAll(){
	ConstIterator it = m_EntitySet.begin();
	ConstIterator itEnd = m_EntitySet.end();

	while (it != itEnd) {
		(*it)->m_Parent = NULL; 
		++it;
	}
	
	m_EntitySet.erase(m_EntitySet.begin(), m_EntitySet.end());
}

bool TScene::hasEntity(TEntity* child){
	ConstIterator it = m_EntitySet.begin();
	ConstIterator itEnd = m_EntitySet.end();

	while (it != itEnd) {
		if ( (*it) == child ){
			return true;
		}
		++it;
	}
	
	return false;
}

TSceneCache* TScene::getParent(){
	return m_Parent;
}

void TScene::getEntitySet(std::set<TEntity*>& r_EntSet){
	ConstIterator it = m_EntitySet.begin();
	ConstIterator itEnd = m_EntitySet.end();
	r_EntSet.clear();
	while (it != itEnd) {
		r_EntSet.insert(*it);
		++it;
	}
}

TEntity* TScene::getEntity(unsigned int uid){
	ConstIterator it = m_EntitySet.begin();
	ConstIterator itEnd = m_EntitySet.end();

	while (it != itEnd) {
		TEntity* entity = (*it)->getEntity(uid);
		if( entity!=NULL ){
			return entity;
		}
		++it;
	}
	
	return NULL;
}



TSceneCache::TSceneCache():m_CurrentScene(""),m_LastActiveScene(""){}

TSceneCache::~TSceneCache(){
	removeAll();
}

bool TSceneCache::contains(std::string key){
	std::map<std::string, TScene* >::iterator it;
	for ( it=m_SceneMap.begin() ; it != m_SceneMap.end(); it++ ){
		if((*it).first==key){
			return true;	
		}
	}
	return false;
}

void TSceneCache::update(){
	TScene* scene = getActiveScene();
	
	if (m_LastActiveScene != m_CurrentScene){
		if(contains(m_LastActiveScene)){
			m_SceneMap[m_LastActiveScene]->hide();
		}
		if (scene != NULL){
			m_LastActiveScene = m_CurrentScene;
			scene->show();
		}
	}
	
	
	if (scene != NULL){
		scene->update();
	}
}

void TSceneCache::setCamera(){
	TScene* scene = getActiveScene();
	if (scene != NULL){
		scene->getCamera()->action();
	}
}

void TSceneCache::render(){
	TScene* scene = getActiveScene();
	if (scene != NULL){
		//scene->getCamera()->action();
		scene->render();
	}
}
	
int TSceneCache::addScene(std::string key,TScene* scene){
	if (contains(key) || key == "" || m_CurrentScene == key){
		return -1;
	}
	
	if(scene->m_Parent != NULL){
		scene->m_Parent->removeScene(scene->getName());
	}
	
	m_SceneMap[key] = scene;
	scene->m_Parent = this;
	scene->setName(key);
	return 0;
}

TScene* TSceneCache::getScene(std::string key){
	if (contains(key)){
		return m_SceneMap[key];
	}
	
	return NULL;
}

void TSceneCache::removeScene(std::string key){
	if (contains(key)){
		m_SceneMap[key]->m_Parent = NULL;
		m_SceneMap.erase(key);
		if (m_CurrentScene == key){
			m_CurrentScene = "";
		}
	}
}

bool TSceneCache::setActiveScene(std::string key){
	if (contains(key)){
		m_LastActiveScene = m_CurrentScene;
		m_CurrentScene = key;
		return true;
	}
	return false;
}

TScene* TSceneCache::getActiveScene(){
	if (m_CurrentScene != ""){
		return m_SceneMap[m_CurrentScene];
	}
	return NULL;
}

void TSceneCache::getSceneList(std::vector<std::string>& list){
	list.clear();
	std::map<std::string, TScene* >::iterator it;
	for ( it=m_SceneMap.begin() ; it != m_SceneMap.end(); it++ ){
		list.push_back((*it).first);
	}
}

void TSceneCache::removeAll(){
	std::map<std::string, TScene* >::iterator it;
	for ( it=m_SceneMap.begin() ; it != m_SceneMap.end(); it++ ){
		(*it).second->m_Parent = NULL;
	}
	m_SceneMap.clear();
}




}
